package Interpreter;

import Interpreter.Function.Function;
import java.util.HashMap;

/**
 *
 * @author Stephen
 */
public class SymbolTable {

    private HashMap<String, Object> symbols;
    private HashMap<String, Function> functions;
    private HashMap<String, String> varType;
    private HashMap<String, DSSObject> dssobjs;
    private SymbolTable parent;

    public SymbolTable() {
        symbols = new HashMap<String, Object>();
        functions = new HashMap<String, Function>();
        varType = new HashMap<String, String>();
        dssobjs = new HashMap<String, DSSObject>();
        parent = null;
    }
    
    public SymbolTable(SymbolTable parent) {
        symbols = new HashMap<String, Object>();
        functions = new HashMap<String, Function>();
        varType = new HashMap<String, String>();
        dssobjs = new HashMap<String, DSSObject>();
        this.parent = parent;
    }
    
    public void addSymbol(String variable, Object value, String type) {
        symbols.put(variable, value);
        varType.put(variable, type);
    }

    public Object getValue(String variable) {
        if (symbols.containsKey(variable)) {
            return symbols.get(variable);
        } else if (parent != null) {
            return parent.getValue(variable);
        } else {
            return null;
        }
    }
    
    public String getType(String variable) {
        if (varType.containsKey(variable)) {
            return varType.get(variable);
        } else if (parent != null) {
            return parent.getType(variable);
        } else {
            return null;
        }
    }
    
    public SymbolTable getParent() {
        return parent;
    }
    
    public void addFunction(String funcName, Function function) {
        functions.put(funcName, function);
    }
    
    public Function getFunction(String funcName) {
        if (functions.containsKey(funcName)) {
            return functions.get(funcName);
        } else if (parent != null) {
            return parent.getFunction(funcName);
        } else {
            System.out.println("Function Not Found: " + funcName); //for debug
            return null;
        }
    }
    
    public void addObject(String objname, DSSObject obj) {
        dssobjs.put(objname, obj);
    }
    
    public DSSObject getObject(String objname) {
        if(dssobjs.containsKey(objname)) {
            return dssobjs.get(objname);
        } else if (parent != null) {
            return parent.getObject(objname);
        } else {
            System.out.println("Object not found"); // for debug
            return null;
        }
    }
    
    public static class Scope {
        private static SymbolTable symbols;
        
        public static void init() {
            symbols = new SymbolTable();
        }
        
        public static void newScope() {
            SymbolTable newTable = new SymbolTable(symbols);
            symbols = newTable;        
        }
        
        public static void closeScope() {
            symbols = symbols.getParent();
        }
        
        public static void addSymbol(String variable, Object value, String type) {
            symbols.addSymbol(variable, value, type);
        }
        
        public static Object getVarValue(String variable) {
            return symbols.getValue(variable);
        }
        
        public static String getVarType(String variable) {
            return symbols.getType(variable);
        }
        
        public static void addFunction(String funcName, Function function) {
            symbols.addFunction(funcName, function);
        }
        
        public static Function getFunction(String funcName) {
            return symbols.getFunction(funcName);
        }
        
        public static void addObject(String objName, DSSObject obj) {
            symbols.addObject(objName, obj);
        }
        
        public static Object getObject(String objName) {
            return symbols.getObject(objName);
        }        
    }
}